package com.cencat.common.utils;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import java.util.Set;

/**
 * 验证工具类
 * 基于JSR-303 Bean Validation规范
 */
public class ValidateUtils {
    
    private static final Validator validator;
    
    static {
        try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) {
            validator = factory.getValidator();
        }
    }
    
    private ValidateUtils() {
        // 私有构造器
    }
    
    /**
     * 验证对象
     * @param obj 要验证的对象
     * @param <T> 对象类型
     * @return 验证结果，如果通过返回null，否则返回错误信息
     */
    public static <T> String validate(T obj) {
        if (obj == null) {
            return "对象不能为空";
        }
        
        Set<ConstraintViolation<T>> violations = validator.validate(obj);
        if (violations.isEmpty()) {
            return null;
        }
        
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<T> violation : violations) {
            sb.append(violation.getPropertyPath()).append(": ")
              .append(violation.getMessage()).append("; ");
        }
        return sb.toString();
    }
    
    /**
     * 验证对象并抛出异常
     * @param obj 要验证的对象
     * @param <T> 对象类型
     */
    public static <T> void validateAndThrow(T obj) {
        String error = validate(obj);
        if (error != null) {
            throw new IllegalArgumentException(error);
        }
    }
    
    /**
     * 验证分组
     * @param obj 要验证的对象
     * @param groups 验证分组
     * @param <T> 对象类型
     * @return 验证结果
     */
    public static <T> String validateGroups(T obj, Class<?>... groups) {
        if (obj == null) {
            return "对象不能为空";
        }
        
        Set<ConstraintViolation<T>> violations = validator.validate(obj, groups);
        if (violations.isEmpty()) {
            return null;
        }
        
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<T> violation : violations) {
            sb.append(violation.getPropertyPath()).append(": ")
              .append(violation.getMessage()).append("; ");
        }
        return sb.toString();
    }
    
    /**
     * 验证特定属性
     * @param obj 要验证的对象
     * @param propertyName 属性名
     * @param <T> 对象类型
     * @return 验证结果
     */
    public static <T> String validateProperty(T obj, String propertyName) {
        if (obj == null) {
            return "对象不能为空";
        }
        if (StringUtils.isBlank(propertyName)) {
            return "属性名不能为空";
        }
        
        Set<ConstraintViolation<T>> violations = validator.validateProperty(obj, propertyName);
        if (violations.isEmpty()) {
            return null;
        }
        
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<T> violation : violations) {
            sb.append(violation.getPropertyPath()).append(": ")
              .append(violation.getMessage()).append("; ");
        }
        return sb.toString();
    }
    
    /**
     * 验证值
     * @param beanType Bean类型
     * @param propertyName 属性名
     * @param value 属性值
     * @param <T> Bean类型
     * @return 验证结果
     */
    public static <T> String validateValue(Class<T> beanType, String propertyName, Object value) {
        if (beanType == null) {
            return "Bean类型不能为空";
        }
        if (StringUtils.isBlank(propertyName)) {
            return "属性名不能为空";
        }
        
        Set<ConstraintViolation<T>> violations = validator.validateValue(beanType, propertyName, value);
        if (violations.isEmpty()) {
            return null;
        }
        
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<T> violation : violations) {
            sb.append(violation.getPropertyPath()).append(": ")
              .append(violation.getMessage()).append("; ");
        }
        return sb.toString();
    }
    
    /**
     * 验证手机号
     * @param mobile 手机号
     * @return 是否有效
     */
    public static boolean isValidMobile(String mobile) {
        return StringUtils.isMobile(mobile);
    }
    
    /**
     * 验证邮箱
     * @param email 邮箱
     * @return 是否有效
     */
    public static boolean isValidEmail(String email) {
        return StringUtils.isEmail(email);
    }
    
    /**
     * 验证身份证号（简单验证）
     * @param idCard 身份证号
     * @return 是否有效
     */
    public static boolean isValidIdCard(String idCard) {
        if (StringUtils.isBlank(idCard)) {
            return false;
        }
        
        // 15位或18位
        if (idCard.length() != 15 && idCard.length() != 18) {
            return false;
        }
        
        // 18位身份证验证最后一位校验码
        if (idCard.length() == 18) {
            char[] idCardArray = idCard.toCharArray();
            
            // 前17位必须是数字
            for (int i = 0; i < 17; i++) {
                if (!Character.isDigit(idCardArray[i])) {
                    return false;
                }
            }
            
            // 最后一位可以是数字或X
            char lastChar = idCardArray[17];
            if (!Character.isDigit(lastChar) && lastChar != 'X' && lastChar != 'x') {
                return false;
            }
        } else {
            // 15位身份证全部必须是数字
            for (char c : idCard.toCharArray()) {
                if (!Character.isDigit(c)) {
                    return false;
                }
            }
        }
        
        return true;
    }
    
    /**
     * 验证URL
     * @param url URL地址
     * @return 是否有效
     */
    public static boolean isValidUrl(String url) {
        if (StringUtils.isBlank(url)) {
            return false;
        }
        
        try {
            new java.net.URL(url);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 验证IP地址
     * @param ip IP地址
     * @return 是否有效
     */
    public static boolean isValidIp(String ip) {
        if (StringUtils.isBlank(ip)) {
            return false;
        }
        
        String regex = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
        return ip.matches(regex);
    }
    
    /**
     * 验证端口号
     * @param port 端口号
     * @return 是否有效
     */
    public static boolean isValidPort(int port) {
        return port > 0 && port <= 65535;
    }
    
    /**
     * 验证文件扩展名
     * @param filename 文件名
     * @param allowedExtensions 允许的扩展名
     * @return 是否允许
     */
    public static boolean isValidFileExtension(String filename, String[] allowedExtensions) {
        if (StringUtils.isBlank(filename) || allowedExtensions == null || allowedExtensions.length == 0) {
            return false;
        }
        
        String extension = getFileExtension(filename);
        if (StringUtils.isBlank(extension)) {
            return false;
        }
        
        for (String allowed : allowedExtensions) {
            if (allowed.equalsIgnoreCase(extension)) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 获取文件扩展名
     * @param filename 文件名
     * @return 扩展名
     */
    private static String getFileExtension(String filename) {
        if (StringUtils.isBlank(filename)) {
            return "";
        }
        
        int lastDotIndex = filename.lastIndexOf('.');
        if (lastDotIndex == -1 || lastDotIndex == filename.length() - 1) {
            return "";
        }
        
        return filename.substring(lastDotIndex + 1).toLowerCase();
    }
    
    /**
     * 验证数字范围
     * @param number 数字
     * @param min 最小值
     * @param max 最大值
     * @return 是否在范围内
     */
    public static boolean isInRange(Number number, Number min, Number max) {
        if (number == null || min == null || max == null) {
            return false;
        }
        
        double value = number.doubleValue();
        double minValue = min.doubleValue();
        double maxValue = max.doubleValue();
        
        return value >= minValue && value <= maxValue;
    }
    
    /**
     * 验证字符串长度
     * @param str 字符串
     * @param minLength 最小长度
     * @param maxLength 最大长度
     * @return 是否在长度范围内
     */
    public static boolean isLengthInRange(String str, int minLength, int maxLength) {
        if (str == null) {
            return minLength <= 0;
        }
        
        int length = str.length();
        return length >= minLength && length <= maxLength;
    }
}